# models.py

from google.appengine.ext import db
import logging

from django.utils import simplejson

class Account(db.Model):
    name = db.StringProperty(required=True)
    type = db.StringProperty()
    amount = db.FloatProperty(required=True)
    owner = db.StringProperty(required=True)

    created_on = db.DateTimeProperty(auto_now_add=True)
    updated_on = db.DateTimeProperty(auto_now_add=True)
    
    @staticmethod
    def all_by_owner(owner):
        return Account.all().filter('owner = ', owner).order("type")

class Transaction(db.Model):
    description = db.StringProperty(multiline=True)
    amount = db.FloatProperty(required=True)
    account = db.ReferenceProperty(Account, required=True)
    is_income = db.BooleanProperty(required=True)
    favorite = db.BooleanProperty(default=False)
    tag = db.StringProperty()
    transaction_date = db.DateTimeProperty(auto_now_add=True)

    created_on = db.DateTimeProperty(auto_now_add=True)
    updated_on = db.DateTimeProperty(auto_now_add=True)

    @staticmethod
    def count_by_account(account):
        return Transaction.all().filter('account = ', account).count()

    @staticmethod
    def all_by_account(account, tag, favorite, min_date, max_date, order = 'transaction_date', asc = 'DESC', page_size = 1000, offset = 0, is_income = None, min_amount = None, max_amount = None):

        gql_str = "WHERE account=:1"

        if tag:
            gql_str = gql_str + " and tag='" + tag.name + "'"
        if favorite:
            gql_str = gql_str + " and favorite=True"
        if is_income != None:
            gql_str = gql_str + " and is_income=" + str(is_income)
        if min_date:
            gql_str = gql_str + " and transaction_date >=DATE('" + min_date + "')"
        if max_date:
            gql_str = gql_str + " and transaction_date <=DATE('" + max_date + "')"

        if not min_date and not max_date:
            if min_amount:
                gql_str = gql_str + " and amount >=" + str(float(min_amount)) # Avoid integer, such as '100' that need to be '100.00'
            if max_amount:
                gql_str = gql_str + " and amount <=" + str(float(max_amount))

        if not min_amount and not max_amount:
            gql_str = gql_str + ' ORDER BY ' + order + ' ' + asc # If has amount filter, can't order by transaction_date

        return Transaction.gql(gql_str, account).fetch(page_size, offset = offset)

    @staticmethod
    def all_by_account_json(account, tag, favorite, min_date, max_date, page, page_size, order = 'transaction_date', asc = 'DESC', is_income = None, min_amount = None, max_amount = None):

        transaction_count = Transaction.count_by_account(account)
        max_page = (transaction_count + page_size - 1) / page_size
        if page > max_page:
            page = max_page
        if page <= 0:
            page = 1
        offset = (page - 1) * page_size

        transactions = Transaction.all_by_account(account, tag, favorite, min_date, max_date, order, asc, page_size, offset, is_income, min_amount = min_amount, max_amount = max_amount)

        transactions_amount = 0
        for transaction in transactions:
            if transaction.is_income:
                transactions_amount = transactions_amount + transaction.amount
            else:
                transactions_amount = transactions_amount - transaction.amount

        return simplejson.dumps(
                {"account_id": account.key().id(),
                 "account_name": account.name,
                 "current_page": str(page), 
                 "max_page": str(max_page), 
                 "count": str(transaction_count), 
                 "account_amount": str(account.amount),
                 "transactions_amount": str(transactions_amount),
                 "records": simplejson.dumps(transactions, default=lambda o: {
                    'transaction_id': str(o.key().id()),
                    'description': o.description,
                    'amount': o.amount,
                    'is_income': o.is_income and 'in' or 'out',
                    'favorite': str(o.favorite),
                    'tag': o.tag,
                    'transaction_date': str(o.transaction_date)
                    })
                 })

    @staticmethod
    def all_by_owner_json(owner, tag, favorite, min_date, max_date, page, page_size, order = 'transaction_date', asc = 'DESC', account_name = None, is_income = None, min_amount = None, max_amount = None):
        accounts = Account.all_by_owner(owner)

        transaction_list_json = []
        for account in accounts:
            if account_name:
                if account.name == account_name:
                    transaction_list_json.append(Transaction.all_by_account_json(account, tag, favorite, min_date, max_date, page, page_size, order, asc, is_income = is_income, min_amount = min_amount, max_amount = max_amount))
            else:
                transaction_list_json.append(Transaction.all_by_account_json(account, tag, favorite, min_date, max_date, page, page_size, order, asc, is_income = is_income, min_amount = min_amount, max_amount = max_amount))

        return simplejson.dumps(transaction_list_json)

class Tag(db.Model):
    name = db.StringProperty(required=True)
    owner = db.StringProperty(required=True)
    count = db.IntegerProperty(required=True)

    created_on = db.DateTimeProperty(auto_now_add=True)
    updated_on = db.DateTimeProperty(auto_now_add=True)
    
    @staticmethod
    def all_by_owner(owner):
        return Tag.all().filter('owner = ', owner).order("name")

    @staticmethod
    def is_exist(name, owner):
        count = Tag.all().filter('name = ', name).filter('owner = ', owner).count()
        return True if count > 0 else False

    @staticmethod
    def get_by_name(name, owner):
        return Tag.all().filter('name = ', name).filter('owner = ', owner).get()
